/* cstr.c - Utility to transform text file into compilable C array of char.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define     TRUE    (1)
#define     FALSE   (0)

void    Usage()
    {
    fprintf(stderr, "Usage: cstr filename.str\n");
    exit(EXIT_FAILURE);
    }

void    GetTarget(const char* Input, char* Output)
    {
    const char* InFile          = Input;
    char*       LastDot         = NULL;
    
    while((*Output=*InFile++) != '\0')
        {
        if(*Output == '.')
            LastDot = Output;
        ++Output;
        }
    if(LastDot == NULL || strcmp(LastDot, ".str"))
        {
        fprintf(stderr, "'%s' does not end in '.str'\n", Input);
        Usage();
        }
    strcpy(LastDot, ".c");
    }

int     LegalChar(char c)
    {
    return isalnum(c) || (c == '_');
    }

int     ParseLine(const char* Input, char* ArrayName, int* ArraySize)
    {
    int     Result  = FALSE;

    if(isalpha(*Input) || *Input == '_')
        {
        while(LegalChar(*Input))
            *ArrayName++  = *Input++;
        *ArrayName  = '\0';

        /* got array name, now skip over white space */
        while(*Input && isspace(*Input))
            ++Input;
        /* now see if array size was specified */
        if(isdigit(*Input))
            *ArraySize  = atoi(Input);
        Result  = TRUE;
        }
    return Result;
    }

char*   AddChar(char* Rover, char C)
    {
    if(isgraph(C) && C != '\\' && C != '\'')
        *Rover++    = C;
    else if(C == ' ')
        *Rover++    = C;
    else
        {
        *Rover++    = '\\';
        switch(C)
            {
            case    '\\'    :   *Rover++    = '\\';     break;
            case    '\b'    :   *Rover++    = 'b';      break;
            case    '\f'    :   *Rover++    = 'f';      break;
            case    '\r'    :   *Rover++    = 'r';      break;
            case    '\n'    :   *Rover++    = 'n';      break;
            case    '\t'    :   *Rover++    = 't';      break;
            case    '\0'    :   *Rover++    = '0';      break;
            case    '\''    :   *Rover++    = '\'';     break;
            default :
                sprintf(Rover, "x%02X", C&0x00FF);
                Rover += 3;
            }
        }

    return Rover;
    }

void    cstr(FILE* Input, FILE* Output, const char* ArrayName, int ArraySize)
    {
    int     Column      = 0;
    int     C;
    int     Eof;

    fprintf(Output, "/* machine generated -- do not edit! */\n");
    fprintf(Output, "char %s[", ArrayName);
    if(ArraySize > 0)
        fprintf(Output, "%d", ArraySize);
    fprintf(Output, "] =\n");
    fprintf(Output, "    {\n");

//    while((C = fgetc(Input)) != EOF)
    for(Eof=FALSE; !Eof;)
        {
        char    Buffer[16];
        char*   Rover = Buffer;

        C           = fgetc(Input);
        if(C == EOF)
            {
            Eof     = TRUE;
            C       = '\0';
            }

        *Rover++    = '\'';
        Rover       = AddChar(Rover, (char)C);
        *Rover++    = '\'';
        *Rover++    = '\0';

        if(Column >= 68)
            {
            fprintf(Output, ",\n");
            Column  = 0;
            }

        if(Column == 0)
            {
            fprintf(Output, "    ");
            }
        else
            {
            fprintf(Output, ",");
            while(++Column % 8)
                fprintf(Output, " ");
            }
        fprintf(Output, "%s", Buffer);
        Column  += strlen(Buffer)+1;
        }

    fprintf(Output, "\n    };\n");
    }


int     main(int argc, char**argv)
    {
    char    Target[1024];
    char    Line[1024];
    char    ArrayName[1024];
    int     ArraySize = -1;
    FILE*   Input;
    FILE*   Output;
    
    
    if(argc != 2)
        Usage();

    Input   = fopen(argv[1], "r");

    if(Input == NULL)
        {
        fprintf(stderr, "Can't open '%s' for reading!\n", argv[1]);
        Usage();
        }

    if( !fgets(Line, sizeof(Line), Input)
    ||  !ParseLine(Line, ArrayName, &ArraySize)
      )
        {
        fprintf(stderr, "First line in file should be of format: array_name [array_size]\n");
        Usage();
        }
    GetTarget(argv[1], Target);
fprintf(stderr, "Target is %s, array '%s'[%d]\n", Target, ArrayName, ArraySize);
    Output  = fopen(Target, "w");
    if(Output == NULL)
        {
        fprintf(stderr, "Unable to open '%s' for writing.\n", Target);
        exit(EXIT_FAILURE);
        }
    cstr(Input, Output, ArrayName, ArraySize);

    exit(EXIT_SUCCESS);
    }
